/*
 * The Yard Utilties - http://www.theyard.net/
 * 
 * Copyright (c) 2008 by Vlideshow, Inc..  All Rights Resrved.
 * 
 * This library is free software; you can redistribute it and/or modify it under the 
 * terms of the GNU Lesser General Public License as published by the Free Software 
 * Foundation; either version 2.1 of the License, or (at your option) any later 
 * version. 
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY 
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along 
 * with this library; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 */
package net.theyard.components.netconnectionsm
{
  import net.theyard.components.netconnectionsm.NetConnectionStateMachine;
  import net.theyard.components.sm.events.StateChangeEvent;

  /**
   * This class can be used by TestCases that need to
   * run some tests once a connection is made to a server
   * but want to abstract away any cases that cause us to
   * fail to connect to a server.
   */
  public class NetConnectionStateMachineTestHelper
  {
    /**
     * The underlying NetConnectionStateMachine that this helper is managing for you.
     */
    public var nc:NetConnectionStateMachine;

    private var callback:Function;
    private var mAsyncWrapperGenerator:Function=null;
    private var mListener:Function = null;

    /**
     * Create a new helper; uses the passed in test case to send
     * any failures to.
     *
     * @param asyncWrapperGenerator If non null the helper will ask this method to generate an event listener that calls a method on our behalf.
     *   for example:
     *   <code>
     * if (this.mAsyncWrapperGenerator != null)
     * {
     *   this.mListener = this.mAsyncWrapperGenerator(this.changeState);
     * }
     * nc.addEventListener(StateChangeEvent.STATE_CHANGE,
     *     this.mListener);
     * </code>
     */
    public function NetConnectionStateMachineTestHelper(asyncWrapperGenerator:Function)
    {
      super();
      mAsyncWrapperGenerator = asyncWrapperGenerator;
      nc = new NetConnectionStateMachine();
    }
    /**
     * Registers the call back function and calls it back when a connection to the server is made.
     *
     * @param callback The function you want the helper to call once a successful connection is made.
     * @param args Arguments to NetConnectionStateMachine#connect()
     *
     * @see NetConnectionStateMachine#connect()
     */
    public function connect(callback:Function, ...args) : void
    {
      if (callback == null)
      {
        // it really doesn't make sense to use this class if
        // you're not using a callback.
        throw new ArgumentError("Got null callback");
      }
      this.callback = callback;
      this.mListener = this.changeState;
      if (this.mAsyncWrapperGenerator != null)
      {
        this.mListener = this.mAsyncWrapperGenerator(this.changeState);
      }
      nc.addEventListener(StateChangeEvent.STATE_CHANGE,
          this.mListener);
      // now go ahead and try to connect.
      nc.connect.apply(nc, args);
    }

    /**
     * Called by the NetConnectionStateMachine the helper manages when state change
     * events occur.
     *
     * Called by the NetConnectionStateMachine when a state change occurs.
     * <p>
     * This is the workhorse that calls the registered call back if a
     * a successful connection is made, and fails if a connection fails.
     * </p>
     * <p>
     * If you derive from this method be sure to call it back to ensure
     * the helper is working as it should.
     * </p>
     */
    public function changeState(event : StateChangeEvent) : void
    {
      var state :String = event.getState();

      switch (state)
      {
        case NetConnectionStateMachine.STATE_CONNECTING:
          // ignore;
          break;
        case NetConnectionStateMachine.STATE_CONNECTED:
          if (this.callback != null)
          {
            this.callback(nc);
            this.callback = null;
            nc.removeEventListener(StateChangeEvent.STATE_CHANGE, this.mListener);
            this.mListener = null;
          }
          break;
        default:
          if (this.callback != null)
          {
            // Got an event we shouldn't have gotten.
            throw new Error("Could not connect to: " + nc.uri);
            this.callback = null;
          }
          break;
      }
    }
  }
}
